/*

* 作者：陈杨
* 时间：2024年9月3日
* 邮箱：chenyang.it@outlook.com
* 工具用途：通过nmon输出的日志文件计算磁盘一致性

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 允许的浮动范围根据实际用例调整
#define ALLOW 0.1
#define UP (1+ALLOW)
#define LOW (1-ALLOW)
// 需要取样1800个数据，从哪一行开始到哪一行结束，选取稳定的数据区间
#define STARTNO 31
#define ENDNO (STARTNO+1799)

const char* nmon_data_csv = "localhost_data.csv";
const char* nmon_title_csv = "localhost_titles.csv";

double ipos[1800];

// read nmon file and extract disk data
void read_nmon(const char* nmon_file) {
    FILE* fp = fopen(nmon_file, "r");
    if (fp == NULL) {
        printf("Failed to open file %s\n", nmon_file);
        return;
    }
    char line[1024];
    FILE* data_fp = fopen(nmon_data_csv, "w");
    FILE* title_fp = fopen(nmon_title_csv, "w");
    while (fgets(line, sizeof(line), fp)!= NULL) {
        // printf("%s", line);
        if(strstr(line, "DISKXFER,Disk") != NULL) {
            char* p = strstr(line, "DISKXFER,Disk");
            fputs(line, title_fp);
        }
        if(strstr(line, "DISKXFER,T") != NULL){
            char* p = strstr(line, "DISKXFER,T");
            fputs(line, data_fp);
        }      
    }
    fclose(fp);
    fclose(data_fp);
    fclose(title_fp);
}

// get index of disk partition in nmon file
int disk_parttion_index(const char* disk_name) {
    FILE* title_fp = fopen(nmon_title_csv, "r");
    if (title_fp == NULL) {
        printf("Failed to open file %s\n", nmon_title_csv);
    }
    char line[1024];
    char *colume[50];
    const char delimiter[] = ",";
    fgets(line, sizeof(line), title_fp); 
    printf("%s\n", line);
    int i = 0;
    char* token = strtok(line, delimiter);
    while (token!= NULL) {
        colume[i] = token;
        i++;
        token = strtok(NULL, delimiter);
    }
    fclose(title_fp);

    for (int i = 0; i < 20; i++) {
        if (colume[i]!= NULL && strstr(colume[i], disk_name) != NULL) {
            return i;
        }
    }
    return -1;  
}

// get iops data from nmon file
void get_iops_from_nmon(int index, double* iops) {
    FILE* data_fp = fopen(nmon_data_csv, "r");
    if (data_fp == NULL) {
        printf("Failed to open file %s\n", nmon_data_csv); 
    }

    char line[1024];
    char *colume[50];
    const char delimiter[] = ",";
    
    int count = 1;
    while (fgets(line, sizeof(line), data_fp)!= NULL)
    {
        if (count >= STARTNO && count <= ENDNO) 
        {
            char* token=strtok(line,delimiter);
            int i=0;
            while(token!=NULL)
            {
                colume[i]=token;
                i++;
                token=strtok(NULL,delimiter);
            }
            iops[count-STARTNO] = atof(colume[index]);         
        }
        count++;
    }
    fclose(data_fp);
}        
// calculate average iops
double calculate_iops_avg(double* iops) {
    double sum = 0.0;
    for (int i = 0; i < 1800; i++) {
        sum += iops[i];
    }
    return sum/1800;
}

// calculate count of iops in range [low, up]
int calculate_range_countof_iops(double* iops, double avg ,double low, double up) {
    int count = 0;
    for (int i = 0; i < 1800; i++) {
        if (iops[i] >= low*avg && iops[i] <= up*avg) {
            count++;
        }
    }
    return count;
}

int main(int avgc, char** argv) 
{

    const char* disk_parttion_name = argv[1];
    const char* nmon_file = argv[2];
    if(avgc!= 3)
    { 
        printf("Usage: %s disk_parttion_name nmon_file\n", argv[0]);
        return 1;   
    }
    printf("disk_parttion_name is %s\n", disk_parttion_name);
    printf("nmon_file is %s\n", nmon_file);
    read_nmon(nmon_file);
    int index = disk_parttion_index(disk_parttion_name);
    printf("index of %s is %d\n", disk_parttion_name, index);
    get_iops_from_nmon(index,ipos);
    double avg = calculate_iops_avg(ipos);
    printf("average iops is %f\n", avg);
    int count = calculate_range_countof_iops(ipos, avg, LOW, UP);
    printf("count of iops in range [%.1f%%, %.1f%%] is %d\n", LOW*100, UP*100, count);
    printf("consistency rate is %.1f%%\n", (float)count/1800*100);
    return 0;
}